#include	"lp_global_vars.h"
#include	"config_parser.h"

config_info *config_info_sample = NULL;
config_info * get_config_info() {
	return config_info_sample;
}
void parse_configuration(const char * config_path, int acceptor_id, int proposer_id, int learner_id) {

	char flag;
	char *match;
	config_info_sample = malloc(sizeof(config_info));
	assert(config_info_sample != NULL);

	config_info_sample->self_acceptor_id = (node_id_t) acceptor_id;
	config_info_sample->self_proposer_id = (node_id_t) proposer_id;
	config_info_sample->self_learner_id = (node_id_t) learner_id;

	match = "num_proposers";
	read_a_number(config_path, get_config_info(), match);

	match = "acceptor";
	flag = 'a';
	get_ip_port(config_path, get_config_info(), match, flag);

	match = "learner_to_acceptor";
	flag = 't';
	get_ip_port(config_path, get_config_info(), match, flag);

	match = "learner";
	flag = 'l';
	get_ip_port(config_path, get_config_info(), match, flag);
	config_info_sample->ring_size = config_info_sample->total_num_acceptors + config_info_sample->total_num_learners;
	//create sockets to receive and forward packets among learners
	create_socket_lp_ring(config_info_sample);

	//create_socket_for_learner_tcp_acceptor(config_info_sample);

}
void read_a_number(const char* config_file, config_info * config, const char * match) {
	FILE * fp;
	char line[STRING_SIZE];
	char word[STRING_SIZE];
	int last_index = -1;

	fp = fopen(config_file, "r");
	assert(fp != NULL);

	while (!feof(fp)) {
		if (fgets(line, STRING_SIZE, fp) != 0) {
			last_index = get_substr(0, strlen(line) - 1, line, word);

			if (strcmp(word, match) == 0) {
				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				config->total_num_proposers = atoi(word);
			}
		}
	}
}
void get_ip_port(const char* config_file, config_info * config, const char * match, char flag) {

	FILE * fp;
	char line[STRING_SIZE];
	char word[STRING_SIZE];
	int last_index = -1, node_counter = 0;

	fp = fopen(config_file, "r");
	assert(fp != NULL);
	while (!feof(fp)) {
		if (fgets(line, STRING_SIZE, fp) != 0) {
			last_index = get_substr(0, strlen(line) - 1, line, word);

			if (strcmp(word, match) == 0) {

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if (flag == 'a')
					config->server_infos[node_counter].server_id = (node_id_t) atoi(word);
				else if (flag == 't')
					config->learner_to_acceptor[node_counter].learner_id = (node_id_t) atoi(word);
				else if (flag == 'l')
					config->learner_infos[node_counter].learner_id = (node_id_t) atoi(word);

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if (flag == 'a')
					memcpy(config->server_infos[node_counter].ip, word, strlen(word));
				else if (flag == 't')
					config->learner_to_acceptor[node_counter].acceptor_id = (node_id_t) atoi(word);
				else if (flag == 'l')
					memcpy(config->learner_infos[node_counter].ip, word, strlen(word));

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if (flag == 'a')
					config->server_infos[node_counter].port = atoi(word);
				else if (flag == 't')
					config->learner_to_acceptor[node_counter].acceptor_port = atoi(word);
				else if (flag == 'l')
					config->learner_infos[node_counter].port = atoi(word);

				node_counter++;
			}
		}
	}
	if (flag == 'a')
		config->total_num_acceptors = node_counter;
	else if (flag == 'p')
		config->total_num_proxies = node_counter;
	else if (flag == 't' || flag == 'l')
		config->total_num_learners = node_counter;

	fclose(fp);
}
void create_socket_for_learner_tcp_acceptor(config_info *config) {
	//socket for the learner to connect to the corresponding acceptor to ask for retransmissions: TCP
	printf("Learner, creating TCP client socket to the acceptor for lost packets.....%d %s %d\n", config->learner_to_acceptor[config->self_learner_id].acceptor_id, config->server_infos[config->learner_to_acceptor[config->self_learner_id].acceptor_id].ip, config->learner_to_acceptor[config->self_learner_id].acceptor_port);
	int port = config->learner_to_acceptor[config->self_learner_id].acceptor_port;
	char *ip = config->server_infos[config->learner_to_acceptor[config->self_learner_id].acceptor_id].ip;
	config->learner_to_acceptor_sid = create_tcp_client_socket(ip, port);
	printf("TCP socket successfully created at: %d\n", config->learner_to_acceptor_sid);
}
void create_socket_lp_ring(config_info *config) {

	int self_id = config->self_learner_id;
	int successor_id = config->self_learner_id + 1;

	printf("Learner, creating TCP socket to receive packets IP: %s port: %d\n", config->learner_infos[self_id].ip, config->learner_infos[self_id].port);
	config->learner_infos[self_id].self_sid = create_tcp_server_socket(config->learner_infos[self_id].ip, config->learner_infos[self_id].port);
	//config->learner_infos[self_id].self_sid = create_udp_server_socket(config->learner_infos[self_id].ip, config->learner_infos[self_id].port, &(config->learner_infos[self_id].ring_self_address));

	if (config->self_learner_id < (config->total_num_learners - 1)) {
		printf("Learner, creating TCP socket to forward packets to IP: %s port: %d\n", config->learner_infos[(config->self_learner_id + 1)].ip, config->learner_infos[successor_id].port);
		config->learner_infos[config->self_learner_id].successor_sid = create_tcp_client_socket(config->learner_infos[successor_id].ip, config->learner_infos[successor_id].port);
		//config->learner_infos[config->self_learner_id].successor_sid = create_udp_client_socket(config->learner_infos[successor_id].ip, config->learner_infos[successor_id].port, &(config->learner_infos[self_id].ring_successor_address));

	} else {
		successor_id = 0;
		printf("Learner, creating TCP socket to forward packets to IP: %s port: %d\n", config->server_infos[successor_id].ip, config->server_infos[successor_id].port);
		config->learner_infos[config->self_learner_id].successor_sid = create_tcp_client_socket(config->server_infos[successor_id].ip, config->server_infos[successor_id].port);
		//config->learner_infos[config->self_learner_id].successor_sid = create_udp_client_socket(config->server_infos[successor_id].ip, config->server_infos[successor_id].port, &(config->learner_infos[self_id].ring_successor_address));

	}
}

//-------LEARNER------------------------------------
int GET_LEARNER_SID_TCP_TO_ACCEPTOR() {
	return config_info_sample->learner_to_acceptor_sid;
}
int GET_LEARNER_SID_UDP_FROM_PREDECESSOR(int id) {
	return config_info_sample->learner_infos[id].self_sid;
}
//-------PROPOSER------------------------------------
int GET_PROPOSER_SID_UDP_TO_ACCEPTOR_0(int id) {
	return config_info_sample->proposer_infos[id].proposer_to_acceptor_0_sid;
}
